import base64
import pickle
import json


from django import http

from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection


from goods.models import SKU
from meiduo_mall.utils.response_code import RETCODE

class CartsSimpleView(View):
    '''商品右上角购物车'''
    def get(self,request):
        user=request.user
        if user.is_authenticated:
            # 用户已登录，查询 Redis 购物车
            redis_conn = get_redis_connection('carts')
            item_dict = redis_conn.hgetall('carts_%s' % user.id)
            cart_selected = redis_conn.smembers('selected_%s' % user.id)

            # 将 redis 中的两个数据统一格式，跟 cookie 中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in item_dict.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 用户未登录，查询 cookie 购物车
            cookie_cart = request.COOKIES.get('carts')
            if cookie_cart:
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                cart_dict = {}

            # 构造简单购物车 JSON 数据
         # 构造简单购物车 JSON 数据
        cart_skus = []
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
             cart_skus.append({
                    'id': sku.id,
                    'name': sku.name,
                    'count': cart_dict.get(sku.id).get('count'),
                    'default_image_url': sku.default_image_url
            })

                # 响应 json 列表数据
        return http.JsonResponse({'code': RETCODE.OK,
                                         'errmsg': 'OK',
                                         'cart_skus': cart_skus})


class CartsSelectAllView(View):
    '''全选购物车'''
    def put(self,request):
        #接收参数
        json_dict=json.loads(request.body.decode())
        selected=json_dict.get('selected',True)
        #校验参数
        if selected:#如果选中
            if not isinstance(selected,bool):
                return http.HttpResponseForbidden('参数selected有误！')
        #判断用户是否登录
        user=request.user
        if user.is_authenticated():
            #用户已经登录，操作Redis购物车
            redis_conn=get_redis_connection('carts')
            item_dict=redis_conn.hgetall('carts_%s'%user.id)#从hash里面获取所有商品
            sku_ids=item_dict.keys()
            if selected:
                #全选
                redis_conn.sadd('selected_%s'%user.id,*sku_ids)#selected是True,就是全选
            else:
                #取消全选
                redis_conn.srem('selected_%s'%user.id,*sku_ids)#selected是False,就是全不选
            return http.JsonResponse({'code':RETCODE.OK,
                                      'errmsg':'全选购物车成功'})
        else:
            #用户未登录，操作cookie购物车
            cookie_cart=request.COOKIES.get('carts')
            response=http.JsonResponse({'code':RETCODE.OK,'errmsg':'全选购物车成功'})
            if cookie_cart:
                cart_dict=pickle.loads(base64.b64decode(cookie_cart.encode()))

                for sku_id in cart_dict:
                    cart_dict[sku_id]['selected']=selected
                cart_data=base64.b64encode(pickle.dumps(cart_dict)).decode()

                response.set_cookie('carts',cart_data)
            return response





class CartsView(View):
    '''购物车管理'''
    def delete(self,request):
        '''删除购物车'''
        #接收参数
        json_dict=json.loads(request.body.decode())
        sku_id=json_dict.get('sku_id')
        #判断sku_id 是否存在
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('商品不存在')

        #判断用户是否登录
        user=request.user
        if  user.is_authenticated():
            #用户登录，删除Redis购物车
            redis_conn=get_redis_connection('carts')
            pl=redis_conn.pipeline()
            #删除键，就等价于删除整条记录
            pl.hdel('carts_%s'% user.id,sku_id)#删除hash里面的值
            pl.srem('selected_%s'% user.id,sku_id)#删除set里面的值
            pl.execute()
            #删除后没有响应的数据，只需要响应状态码就可以
            return http.JsonResponse({'code':RETCODE.OK,
                                      'errmsg':'删除购物车成功'})
        else:
            #用户未登录，删除cookie购物车
            cookie_cart=request.COOKIES.get('carts')
            if cookie_cart:
                #如果购物车存在，将购物车转成bytes,在将bytes转成base64的byte，最后转成字典
                cart_dict=pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                cart_dict={}#不存在创建空的
            #创建响应对象
            response=http.JsonResponse({'code':RETCODE.OK,'errmsg':'删除购物车成功'})
            if sku_id in cart_dict:
                del cart_dict[sku_id]
                #将字典转成bytes，再将bytes转成base64的bytes,最后将bytes转成字符串
                cart_data=base64.b64encode(pickle.dumps(cart_dict)).decode()
                #响应结果并将购物车数据写入到cookie
                response.set_cookie('carts',cart_data)
        return response
    def put(self,request):
        '''
         修改购物车数据
         :param request:
         :return:
         '''
        # 1.接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        selected = json_dict.get('selected', True)

        # 2.校验参数
        if not all([sku_id, count]):
            return http.HttpResponseForbidden('缺少必传参数')

        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku_id出错')

        try:
            count = int(count)
        except Exception:
            return http.HttpResponseForbidden('count参数错误')

        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseForbidden('selected参数类型错误')

        #3.判断是否登录
        if request.user.is_authenticated():
            #用户登录
            #4.连接redis
            redis_conn=get_redis_connection('carts')
            pl=redis_conn.pipeline()
            #5.重写hash
            pl.hset('carts_%s'% request.user.id,sku_id,count)
            #6.判断用户发来的是True还是False
            if selected:
                #7.如果为True，增加到set
                pl.sadd('selected_%s'%request.user.id,sku_id)
            else:
                #8.否则 删除set
                pl.srem('selected_%s'%request.user.id,sku_id)
            pl.execute()
            # 9.拼接数据
            sku_dict = {
                'id': sku_id,
                'name': sku.name,
                'default_image_url': sku.default_image_url,
                'price': str(sku.price),
                'count': count,
                'selected': selected,
                'amount': str(sku.price * count)
            }

            # 10.返回
            return http.JsonResponse({'code': RETCODE.OK,
                                      'errmsg': 'ok',
                                      'cart_sku': sku_dict})
        else:
            #用户未登录
            #1.从cookie中获取
            cookie_cart=request.COOKIES.get('carts')
            #2.判断是否存在
            if cookie_cart:
                #如果存在，解密
                cart_dict=pickle.loads(base64.b64decode(cookie_cart))
            else:
                #如果不存在，新建
                cart_dict={}
            #5.把获取的数据，重写进去
            cart_dict[sku_id]={
                'count':count,
                'selected':selected
            }
            #加密
            cart_date=base64.b64encode(pickle.dumps(cart_dict)).decode()


            #返回json
            sku_dict={
                'id': sku_id,
                'name': sku.name,
                'default_image_url': sku.default_image_url,
                'price': str(sku.price),
                'count': count,
                'selected': selected,
                'amount': str(sku.price * count)
            }

        response=http.JsonResponse({'code':RETCODE.OK,
                                    'errmsg':'OK',
                                    'cart_sku':sku_dict})

        #7.写入到cookie
        response.set_cookie('carts',cart_date)
        #8.返回
        return response

    def get(self,request):
         '''
        获取购物车数据
        :param request:
        :return:
        '''
        # 1.判断是否是登录用户
         if request.user.is_authenticated:
            # 2.如果是:
            # 3.链接redis
            redis_conn = get_redis_connection('carts')

            # 4.从hash表中取数据: carts_user_id : {sku_id: count}
            item_dict = redis_conn.hgetall('carts_%s' % request.user.id)

            # 5.从set取  selected_user_id :[sku_id1, ...]
            cart_selected = redis_conn.smembers('selected_%s' % request.user.id)

            # 6.整理格式: 和 cookie一样的格式
            # sku_id:{
            #     'count':个数,
            #     'selected':bool
            # }
            cart_dict = {}
            for sku_id, count in item_dict.items():
                cart_dict[int(sku_id)] = {
                    'count':int(count),
                    'selected': sku_id in cart_selected
                }

         else:
            # 1.从cookie获取
            cookie_cart = request.COOKIES.get('carts')

            # 2.判断是否存在
            if cookie_cart:
                # 3.如果存在, 解密
                cart_dict = pickle.loads(base64.b64decode(cookie_cart))
            else:
                # 4.如果不存在, 创建
                cart_dict = {}

         # 1.获取字典中所有的键
         sku_ids = cart_dict.keys()

         # 2.根据键获取所有的商品
         skus = SKU.objects.filter(id__in=sku_ids)

         skus_list = []
         # 3.遍历商品
         for sku in skus:
            # 4.拿到每一个商品, 拼接参数: 前端要的商品的每一行
             skus_list.append({
                'id':sku.id,
                'name':sku.name,
                'default_image_url':sku.default_image_url,
                'price':str(sku.price),
                'count':cart_dict[sku.id].get('count'),
                'selected':str(cart_dict[sku.id].get('selected')),
                'amount':str(sku.price * cart_dict[sku.id].get('count'))
            })

         # 5.拼接
         context = {
            'cart_skus':skus_list
         }

         # 6.返回
         return render(request, 'cart.html', context)


    def post(self,request):
        '''添加购物车'''
        #1.接收参数
        json_dict=json.loads(request.body.decode())
        sku_id=json_dict.get('sku_id')
        count=json_dict.get('count')
        selected=json_dict.get('selected',True)

        #判断参数是否齐全
        if  not all([sku_id,count]):
            return http.HttpResponseForbidden("缺少必传参数")
        #判断sku_id是否存在
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('商品不存在')
        #判断count是否为数子
        try:
            count=int(count)
        except Exception:
            return http.HttpResponseForbidden('参数count有误')

        #判断selected的值是否为boole
        if selected:
              if not isinstance(selected,bool):
                    return http.HttpResponseForbidden('参数selected有误！')


        #判断用户是否登录
        if request.user.is_authenticated():
            #用户登录，操作redis购物车
            redis_conn=get_redis_connection('carts')
            pl=redis_conn.pipeline()
            #新增购物车数据
            pl.hincrby('carts_%s'% request.user.id,sku_id,count)
            #新增选择状态
            if selected:
                pl.sadd('selected_%s'% request.user.id,sku_id)
            #执行管道
            pl.execute()
            #响应结果
            return http.JsonResponse({'code': RETCODE.OK,
                                      'errmsg': 'ok'})



        else:
            #用户没有登录，操作cookie购物车
            cookie_cart=request.COOKIES.get('carts')
            #未登录时，判断用户是否加入过商品到购物车
            if cookie_cart:#加入过商品到购物车
                #将cookie_cart转成base64的bytes，最有将byte转成字典
                cart_dict = pickle.loads(base64.b64decode(cookie_cart))
            else:
                #用户从来没有操作购物车
                cart_dict={}
            if sku_id in cart_dict:#判断商品 是否在购物车中
                    #累加求和
                count+=cart_dict[sku_id]['count']
            cart_dict[sku_id]={
                'count':count,
                'selected':selected
            }
                # 判断要加入购物车的商品是否已经在购物车中
                # 如有相同商品，累加求和，反之，直接赋值
                # 我们判断用户之前是否将该商品加入过购物车, 如果加入过
                # 则只需要让数量增加即可.
                # 如果没有存在过, 则需要创建, 然后增加:
                # 形式如下所示:
                # {
                #     '<sku_id>': {
                #         'count': '<count>',
                #         'selected': '<selected>',
                #     },
                #     ...
                # }

            cart_data=base64.b64encode(pickle.dumps(cart_dict)).decode()


            #创建响应对象
            response = http.JsonResponse({'code': RETCODE.OK,
                                              'errmsg': 'ok'})

            response.set_cookie('carts', cart_data)

            return  response

